Categories
Vue

Vee-Validate — Localization, and Input Component

Spread the love

Form validation is a feature that’s not built into Vue.js. However, we still need this feature very much. In this article, we’ll look at how to add localization features with Vee-Validate. We also look at how to extract the input component code.

Lazily Import Locales

We can use the import function to import a locale file from Vee-Validate.

For example, we can write:

import { localize } from 'vee-validate';

import(`vee-validate/dist/locale/fr.json`).then(locale => {
  localize(code, locale);
});

Using Other i18n Libraries

Vee-Validate integrates with other i18n libraries. For instance, we can use the vue-i18n library with Vee-Validate.

We can write:

import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, extend } from "vee-validate";
import { required } from "vee-validate/dist/rules";
import en from "vee-validate/dist/locale/en.json";
import VueI18n from "vue-i18n";

Vue.use(VueI18n);

const i18n = new VueI18n({
  locale: "en",
  messages: {
    en: {
      validation: en.messages
    }
  }
});

extend("required", {
  ...required,
  message: (_, values) => i18n.t("validation.required", values)
});

Vue.component("ValidationProvider", ValidationProvider);

Vue.config.productionTip = false;

new Vue({
  i18n,
  render: h => h(App)
}).$mount("#app");

We imported the messages from Vee-Validate.

Then we set them as the property of messages.en.validation .

Then we use i18n.t to translate the message.

Then we can write:

<template>
  <div id="app">
    <ValidationProvider name="name" rules="required" v-slot="{ errors }">
      <input v-model="name" type="text" placeholder="name">
      <span>{{ errors[0] }}</span>
    </ValidationProvider>

<input type="submit" value="submit">
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      name: ""
    };
  }
};
</script>

to display the message.

Model-less Validation

We can validate inputted values without models.

For example, we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, extend } from "vee-validate";
import { required, image } from "vee-validate/dist/rules";

extend("required", required);
extend("image", image);
Vue.component("ValidationProvider", ValidationProvider);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <ValidationProvider rules="required|image" name="file" v-slot="{ validate, errors }">
      <input type="file" @change="validate">
      <p>{{ errors[0] }}</p>
    </ValidationProvider>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

We imported the required and image rules in main.js .

Then we used ValidationProvider in the template.

We called the built-in validate function to validate the file type when it’s changed.

We also have the name prop on the ValidationProvider .

Then we’ll see an error message if it’s not a valid image file.

Custom Component File Validation

Any component that emits an input event can be validated by Vee-Validate.

The value is emitted with the input event.

Value Synchronization

We can synchronize the value manually between what’s entered and what Vee-Validate sees with the syncValue method.

For example, we can write:

this.$refs.provider.syncValue(newValue);

to set the value of the validation provider with newValue .

Dynamic Rules

Rules can be applied dynamically.

We can put an expression in the rules prop.

For example, we can write:

<template>
  <div id="app">
    <button @click="required = !required">{{required ? 'disable':'enable'}} required</button>
    <br>
    <ValidationProvider
      :rules="`${required ? 'required' : ''}`"
      name="value"
      v-slot="{ validate, errors }"
    >
      <input v-model="value" type="text">
      <p>{{ errors[0] }}</p>
    </ValidationProvider>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      value: "",
      required: true
    };
  }
};
</script>

Then when required is false , no validation will be done.

Otherwise, validation will be done.

Extracting Input Fields

We can extract input fields into their own component.

This way, we don’t have to repeatedly reference ValidationProvider .

For example, we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, ValidationObserver, extend } from "vee-validate";
import { required, image } from "vee-validate/dist/rules";

extend("required", required);
extend("image", image);
Vue.component("ValidationProvider", ValidationProvider);
Vue.component("ValidationObserver", ValidationObserver);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

TextInput.vue

<template>
  <ValidationProvider tag="div" :rules="rules" :name="name" :vid="vid" v-slot="{ errors }">
    <input :type="type" v-model="currentValue">
    <span>{{ errors[0] }}</span>
  </ValidationProvider>
</template>

<script>
import { ValidationProvider } from "vee-validate";

export default {
  name: "TextInput",
  components: {
    ValidationProvider
  },
  props: {
    value: {
      type: String,
      default: ""
    },
    rules: {
      type: [String, Object],
      default: ""
    },
    name: {
      type: String,
      default: ""
    },
    vid: {
      type: String,
      default: undefined
    },
    type: {
      type: String,
      default: "text"
    }
  },
  data: () => ({
    currentValue: ""
  }),
  watch: {
    currentValue(val) {
      this.$emit("input", val);
    }
  }
};
</script>

The TextInput component is the component with the form field logic.

It takes various props that are used to populate fields with the data we want.

The value entered with the input event in the currentValue watcher.

It also takes the value prop.

Therefore, it can bind to v-model .

App.vue

<template>
  <div id="app">
    <ValidationObserver v-slot="{ handleSubmit }">
      <form @submit.prevent="handleSubmit(onSubmit)">
        <TextInput v-model="firstName" name="First Name" rules="required"/>

        <TextInput v-model="lastName" name="Last Name" rules="required"/>

        <input type="submit" value="submit">
      </form>
    </ValidationObserver>
  </div>
</template>

<script>
import TextInput from "./components/TextInput";

export default {
  name: "App",
  components: {
    TextInput
  },
  data() {
    return {
      firstName: "",
      lastName: ""
    };
  },
  methods: {
    onSubmit() {
      alert("success");
    }
  }
};
</script>

Then we can use it in the form element like any other input element.

Conclusion

We can add localization and extract form fields into a component.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *